package insert

import (
	"errors"
	"reflect"
	"strings"
)

var errInvalidEntity = errors.New("invalid entity")

// InsertStmt 作业里面我们这个只是生成 SQL，所以在处理 sql.NullString 之类的接口 只需要判断有没有实现 driver.Valuer 就可以了
func InsertStmt(entity interface{}) (string, []interface{}, error) {
	//判断入参是否有效 不可以为nil
	if entity == nil {
		return "", nil, errInvalidEntity
	}

	val := reflect.ValueOf(entity)
	typ := val.Type()
	//判断是否是为指针
	if typ.Kind() == reflect.Pointer {
		val = val.Elem()
		typ = val.Type()
	}

	//判断入参是否为结构体
	if typ.Kind() != reflect.Struct {
		return "", nil, errInvalidEntity
	}

	bd := strings.Builder{}

	bd.WriteString("INSERT INTO `")
	bd.WriteString(typ.Name())
	bd.WriteString("`(")

	fields, values := fieldkeyVal(val)
	for i, name := range fields {
		if i > 0 {
			bd.WriteRune(',')
		}
		bd.WriteRune('`')
		bd.WriteString(name)
		bd.WriteRune('`')
	}

	bd.WriteString(") VALUES(")
	args := make([]interface{}, 0, len(values))
	for i, fd := range fields {
		if i > 0 {
			bd.WriteRune(',')
		}
		bd.WriteRune('?')
		args = append(args, values[fd])
	}
	if len(args) == 0 {
		return "", nil, errInvalidEntity
	}
	bd.WriteString(");")
	return bd.String(), args, nil
}

func fieldkeyVal(val reflect.Value) ([]string, map[string]interface{}) {
	typ := val.Type()
	numField := typ.NumField()
	fields := make([]string, 0, numField)
	values := make(map[string]interface{}, numField)
	for i := 0; i < numField; i++ {
		field := typ.Field(i)
		fieldVal := val.Field(i)
		//是否存在组合
		if field.Type.Kind() == reflect.Struct && field.Anonymous {
			subFields, subValues := fieldkeyVal(fieldVal)
			for _, k := range subFields {
				if _, ok := values[k]; ok {
					//处理重复字段
					continue
				}
				fields = append(fields, k)
				values[k] = subValues[k]
			}
			continue
		}
		fields = append(fields, field.Name)
		values[field.Name] = fieldVal.Interface()
	}
	return fields, values
}
